﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using DDD.Core;
using FloatComparer = DDDTest.Helper.FloatComparer;

namespace DDDTest.Core {
    [TestClass]
    public class TestAnimationTrack {

        [TestMethod]
        public void Test_New1 () {
            var track = new AnimationTrack (4, 3, InterpolationType.Linear);

            Assert.AreEqual (4, track.KeyframeCount);
            Assert.AreEqual (3, track.ComponentCount);
            Assert.AreEqual (InterpolationType.Linear, track.InterpolationType);
            Assert.AreEqual (0, track.Duration);
            Assert.AreEqual (0, track.ValidRange.First);
            Assert.AreEqual (3, track.ValidRange.Last);
            Assert.AreEqual (LoopMode.Single, track.LoopMode);

            var exptected = new float[3] { 0, 0, 0 };

            Assert.AreEqual (0, track.GetKeyframe (0).Position);
            Assert.AreEqual (0, track.GetKeyframe (1).Position);
            Assert.AreEqual (0, track.GetKeyframe (2).Position);
            Assert.AreEqual (0, track.GetKeyframe (3).Position);
            CollectionAssert.AreEqual (exptected, track.GetKeyframe (0).Value);
            CollectionAssert.AreEqual (exptected, track.GetKeyframe (1).Value);
            CollectionAssert.AreEqual (exptected, track.GetKeyframe (2).Value);
            CollectionAssert.AreEqual (exptected, track.GetKeyframe (3).Value);
        }

        [TestMethod]
        public void Test_SetKeyframe () {
            var track = new AnimationTrack (4, 3, InterpolationType.Linear);
            track.SetKeyframe (0, 100, new float[] { 1, 2, 3 });
            track.SetKeyframe (1, 101, new float[] { 4, 5, 6 });
            track.SetKeyframe (2, 102, new float[] { 7, 8, 9 });
            // index3 is not set, but it's valid.

            Assert.AreEqual (4, track.KeyframeCount);
            Assert.AreEqual (100, track.GetKeyframe (0).Position);
            Assert.AreEqual (101, track.GetKeyframe (1).Position);
            Assert.AreEqual (102, track.GetKeyframe (2).Position);
            Assert.AreEqual (0, track.GetKeyframe (3).Position);
            CollectionAssert.AreEqual (new float[] { 1, 2, 3 }, track.GetKeyframe (0).Value);
            CollectionAssert.AreEqual (new float[] { 4, 5, 6 }, track.GetKeyframe (1).Value);
            CollectionAssert.AreEqual (new float[] { 7, 8, 9 }, track.GetKeyframe (2).Value);
            CollectionAssert.AreEqual (new float[] { 0, 0, 0 }, track.GetKeyframe (3).Value);
        }

        [TestMethod]
        public void Test_Keyframes () {
            var track = new AnimationTrack (4, 3, InterpolationType.Linear);
            track.SetKeyframe (0, 100, new float[] { 1, 2, 3 });
            track.SetKeyframe (1, 101, new float[] { 4, 5, 6 });
            track.SetKeyframe (2, 102, new float[] { 7, 8, 9 });
            // index3 is not set, but it's valid one.

            Assert.AreEqual (4, track.KeyframeCount);
            Assert.AreEqual (4, track.Keyframes.Count ());
        }


        [TestMethod]
        public void Test_SetDuration () {
            var track = new AnimationTrack (4, 3, InterpolationType.Linear);
            track.SetDuration (100);

            Assert.AreEqual (100, track.Duration);
        }

        [TestMethod]
        public void Test_SetValidRange () {
            var track = new AnimationTrack (4, 3, InterpolationType.Linear);
            track.SetKeyframe (0, 100, new float[] { 1, 2, 3 });
            track.SetKeyframe (1, 101, new float[] { 4, 5, 6 });
            track.SetKeyframe (2, 102, new float[] { 7, 8, 9 });
            track.SetKeyframe (3, 103, new float[] { 10, 11, 12 });

            track.SetValidRange (0, 0);
            Assert.AreEqual (0, track.ValidRange.First);
            Assert.AreEqual (0, track.ValidRange.Last);

            track.SetValidRange (1, 2);
            Assert.AreEqual (1, track.ValidRange.First);
            Assert.AreEqual (2, track.ValidRange.Last);
        }


        [TestMethod]
        public void Test_SetLoopMode () {
            var track = new AnimationTrack (4, 3, InterpolationType.Linear);
            track.SetLoopMode (LoopMode.AdditiveLoop);

            Assert.AreEqual (LoopMode.AdditiveLoop, track.LoopMode);
        }

        [TestMethod]
        public void Test_AddEvent () {
            var track = new AnimationTrack (4, 3, InterpolationType.Linear);
            var handler = new AnimationEventHandler ((sender, arguments) => {
                // do nothing
            });
            var args = new EventArgs ();

            track.AddEvent (100, handler, args);
            Assert.AreEqual (1, track.EventCount);

            var ev = track.GetEvent (0);
            Assert.AreEqual (100, ev.Position);
            Assert.AreEqual (handler, ev.Handler);
            Assert.AreEqual (args, ev.Args);
        }

        [TestMethod]
        public void Test_RemoveEvent () {
            var track = new AnimationTrack (4, 3, InterpolationType.Linear);
            var handler = new AnimationEventHandler ((sender, arguments) => {
                // do nothing
            });
            var args = new EventArgs ();

            track.AddEvent (100, handler, args);
            Assert.AreEqual (1, track.EventCount);

            var n1 = track.RemoveEvent (handler);
            var n2 = track.RemoveEvent (handler);
            Assert.AreEqual (1, n1);
            Assert.AreEqual (0, n2);
            Assert.AreEqual (0, track.EventCount);
        }

        /// <summary>
        /// アニメーションイベントの発火のテスト
        /// </summary>
        /// <remarks>
        /// [Start,End)はDurationより小さくないといけない
        /// </remarks>
        [TestMethod]
        public void Test_GetActiveEvents () {
            var track = new AnimationTrack (4, 3, InterpolationType.Linear);
            var handler = new AnimationEventHandler ((sender, arguments) => {
                // do nothing
            });
            track.AddEvent (50, handler, null);
            track.SetDuration (100);

            // 境界値付近のテスト
            Assert.AreEqual (0, track.GetRaisingEvents (0, 50).Count ());
            Assert.AreEqual (1, track.GetRaisingEvents (50, 50).Count ());
            Assert.AreEqual (1, track.GetRaisingEvents (50, 100).Count ());

            // 1回モードのテスト
            track.SetLoopMode (LoopMode.Single);
            Assert.AreEqual (0, track.GetRaisingEvents (-99, 0).Count ());
            Assert.AreEqual (1, track.GetRaisingEvents (0, 99).Count ());
            Assert.AreEqual (0, track.GetRaisingEvents (100, 199).Count ());
            Assert.AreEqual (0, track.GetRaisingEvents (0, 50).Count ());
            Assert.AreEqual (1, track.GetRaisingEvents (50, 50).Count ());
            Assert.AreEqual (1, track.GetRaisingEvents (50, 100).Count ());

            // ループモードのテスト
            track.SetLoopMode (LoopMode.Loop);
            Assert.AreEqual (1, track.GetRaisingEvents (-99, 0).Count ());
            Assert.AreEqual (1, track.GetRaisingEvents (0, 99).Count ());
            Assert.AreEqual (1, track.GetRaisingEvents (100, 199).Count ());

        }


    }
}
